package org.dromara.business.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import org.dromara.business.constant.BusinessConstants;
import org.dromara.business.domain.GoodsOrder;
import org.dromara.business.domain.vo.BusinessConfigVo;
import org.dromara.business.domain.vo.UserVo;
import org.dromara.business.service.BusinessConfigService;
import org.dromara.business.service.GoodsOrderService;
import org.dromara.business.service.UserFlowingService;
import org.dromara.business.service.UserService;
import org.dromara.common.core.constant.CacheNames;
import org.dromara.common.core.constant.UserConstants;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.enums.UserType;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.redis.utils.CacheUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.websocket.utils.WebSocketUtils;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.service.ISysUserService;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 用户相关
 *
 * @author zlj
 * @date 2024-08-01
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/business/vip")
public class VipController extends BaseController {

    private final BusinessConfigService configService;
    private final ISysUserService userService;
    private final UserService businessUserService;
    private final UserFlowingService userFlowingService;
    private final GoodsOrderService orderService;

    @GetMapping("/getMyInfo")
    public R<SysUserVo> getMyInfo() {
        SysUser user = userService.getById(LoginHelper.getUserId());
        if (ObjectUtil.isNull(user)) {
            throw new ServiceException("用户不存在", 401);
        }
        SysUserVo vo = BeanUtil.toBean(user, SysUserVo.class);
        //设置vip等级
        List<BusinessConfigVo> vip = configService.queryByKey("vip");
        for (BusinessConfigVo configVo : vip) {
            if (ObjectUtil.equals(configVo.getSortNo(), user.getVip())) {
                vo.setVipName(configVo.getConfigName());
                break;
            }
        }
        List<BusinessConfigVo> vipUrl = configService.queryByKey("vipUrl");
        for (BusinessConfigVo configVo : vipUrl) {
            if (ObjectUtil.equals(configVo.getSortNo(), user.getVip())) {
                vo.setVipUrl(configVo.getUrl());
                break;
            }
        }
        List<GoodsOrder> list = orderService.lambdaQuery().eq(GoodsOrder::getCreateBy, user.getUserId())
            .in(GoodsOrder::getStatus, "2", "3", "4").list();
        vo.setOrder2(list.stream().filter(order -> ObjectUtil.equals(order.getStatus(), "2")).count());
        vo.setOrder3(list.stream().filter(order -> ObjectUtil.equals(order.getStatus(), "3")).count());
        vo.setOrder4(list.stream().filter(order -> ObjectUtil.equals(order.getStatus(), "4")).count());

        if (ObjectUtil.equals(user.getIsWaiter(), "1")) {
            List<GoodsOrder> dsList = orderService.lambdaQuery().eq(GoodsOrder::getWaiterId, user.getUserId())
                .in(GoodsOrder::getStatus, "3", "4").list();
            vo.setDsOrder5(dsList.stream().filter(order -> ObjectUtil.equals(order.getStatus(), "3")).count());
            vo.setDsOrder6(dsList.stream().filter(order -> ObjectUtil.equals(order.getStatus(), "4")).count());
        }
        return R.ok(vo);
    }

    /**
     * 老用户绑定邀请人
     */
    @GetMapping("/bindSuperior")
    public R<Void> bindSuperior(Long userId) {
        Long id = LoginHelper.getUserId();
        SysUser me = userService.getById(id);
        userService.updateById(me);
        return R.ok();
    }


    /**
     * 修改用户头像昵称信息
     *
     * @return 用户信息
     */
    @PostMapping("/updateWxInfo")
    public R<Void> updateWxInfo(String nickName, Long avatar, String info) {
        SysUser user = userService.getById(LoginHelper.getUserId());
        try {
            if (ObjectUtil.isNotNull(user.getAvatar())) {
                CacheUtils.evict(CacheNames.SYS_OSS, user.getAvatar());
            }
            CacheUtils.evict(CacheNames.SYS_NICKNAME, user.getUserId());
        } catch (Exception ignored) {
        }
        userService.lambdaUpdate()
            .set(StrUtil.isNotBlank(nickName), SysUser::getNickName, nickName)
            .set(StrUtil.isNotBlank(info), SysUser::getInfo, info)
            .set(ObjectUtil.isNotNull(avatar), SysUser::getAvatar, avatar)
            .eq(SysUser::getUserId, LoginHelper.getUserId())
            .update();
        return R.ok();
    }

    /**
     * 查询排行榜
     *
     * @param type 排行榜类型 日排行榜:day_amount 周排行榜:week_amount 月排行榜:month_amount
     */
    @GetMapping("/getRankings")
    public R<List<SysUserVo>> getRankings(String type) {
        List<SysUser> userList = userService.lambdaQuery().eq(SysUser::getIsWaiter, 1)
            .eq(SysUser::getStatus, UserConstants.USER_NORMAL)
            .eq(SysUser::getUserType, UserType.XCX_USER.getUserType())
            .last("order by " + type + " desc limit 10")
            .list();
        return R.ok(BeanUtil.copyToList(userList, SysUserVo.class));
    }

    /**
     * 赠送积分
     *
     * @param userId 对方id
     * @param amount 金额
     * @param type   1余额 ，2积分
     */
    @PostMapping("/give")
    public R<Void> give(Long userId, BigDecimal amount, String type) {
        SysUser user = userService.getById(userId);
        if (ObjectUtil.isNull(user) || ObjectUtil.notEqual(user.getUserType(), UserType.XCX_USER.getUserType())) {
            throw new ServiceException("用户不存在");
        }
        if (LoginHelper.isUser()) {
            Long me = LoginHelper.getUserId();
            if (amount.compareTo(BigDecimal.ZERO) <= 0) {
                throw new ServiceException("赠送金额必须大于0");
            }
            //扣除积分
            userFlowingService.addAmount(me, amount.multiply(new BigDecimal("-1")),
                BusinessConstants.FLOWING_TYPE_GIVE, userId, type);
            //赠与积分(需要扣手续费)
            String giveCc = configService.queryValueByKey("give_cc");
            userFlowingService.addAmount(userId, amount.multiply(new BigDecimal(giveCc)), BusinessConstants.FLOWING_TYPE_GIVE, me, type);
            return R.ok();
        }
        if (!LoginHelper.isSuperAdmin()) {
            throw new ServiceException("无权限");
        }
        //赠与积分
        userFlowingService.addAmount(userId, amount, BusinessConstants.FLOWING_TYPE_ADMIN_GIVE, UserConstants.SUPER_ADMIN_ID, type);
        return R.ok();
    }

    @RepeatSubmit(interval = 2000, message = "奖品正在路上...")
    @PutMapping("/cj")
    public R<Void> cj(Long businessConfigId) {
        BusinessConfigVo configVo = configService.queryById(businessConfigId);
        if (ObjectUtil.isNull(configVo)) {
            return R.fail("奖品不存在");
        }
        //减少抽奖次数
        boolean update = userService.lambdaUpdate().eq(SysUser::getUserId, LoginHelper.getUserId())
            .setSql("number_draws=number_draws-1")
            .ge(SysUser::getNumberDraws, 1)
            .update();
        if (!update) {
            return R.fail("抽奖次数不足");
        }
        String[] split = configVo.getConfigName().split("-");
        if (split.length == 1) {
            return toAjax(true);
        }
        //增加积分
        userFlowingService.addAmount(LoginHelper.getUserId(), new BigDecimal(split[1]),
            BusinessConstants.FLOWING_TYPE_CJ, null, BusinessConstants.FLOWING_TYPE_INTEGRAL);
        return toAjax(true);
    }

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    private final String USER_SIGN_KEY = "sign:";

    /**
     * 签到接口
     */
    @GetMapping("/sign")
    @RepeatSubmit()
    @Transactional(rollbackFor = Exception.class)
    public R<Void> sign() {
        //生成key
        String key = this.getKey();
        //获取本月第几天
        int dayOfMonth = DateUtil.dayOfMonth(DateUtils.getNowDate());
        //判断今日是否签到
        //查询redis
        List<Long> result = stringRedisTemplate.opsForValue().bitField(key,
            BitFieldSubCommands.create()
                .get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0));
        if ((result.get(0) & 1) == 1) {
            throw new ServiceException("今日已签到");
        }
        //存到redis
        stringRedisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true);
        //增加积分
        BigDecimal amount = this.getTodayAmount().getData();
        userFlowingService.addAmount(LoginHelper.getUserId(), amount, BusinessConstants.FLOWING_TYPE_RAL_SIGN, null, BusinessConstants.FLOWING_TYPE_INTEGRAL);
        return R.ok();
    }

    /**
     * 判断今天是否打卡
     */
    @GetMapping("/getTodayIsSign")
    public R<Boolean> getTodayIsSign() {
        //生成key
        String key = this.getKey();
        //获取本月第几天
        int dayOfMonth = DateUtil.dayOfMonth(DateUtils.getNowDate());
        //查询redis
        List<Long> result = stringRedisTemplate.opsForValue().bitField(key,
            BitFieldSubCommands.create()
                .get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0));
        return R.ok((result.get(0) & 1) == 1);
    }

    private String getKey() {
        Long userId = LoginHelper.getUserId();
        Date nowDate = DateUtils.getNowDate();
        String keySuffix = DateUtil.format(nowDate, ":yyyyMM:");
        return USER_SIGN_KEY + userId + keySuffix;
    }

    /**
     * 获取本月签到历史
     */
    @GetMapping("/getHistorySign")
    public R<List<String>> getHistorySign() {
        //生成key
        String key = this.getKey();
        //获取本月第几天
        int dayOfMonth = DateUtil.dayOfMonth(DateUtils.getNowDate());
        DateTime firstDay = DateUtil.beginOfMonth(DateUtils.getNowDate());
        // 查询redis
        List<String> signHistory = new ArrayList<>();
        for (int i = 0; i < dayOfMonth; i++) {
            List<Long> result = stringRedisTemplate.opsForValue().bitField(key,
                BitFieldSubCommands.create()
                    .get(BitFieldSubCommands.BitFieldType.unsigned(1))
                    .valueAt(i));
            if (CollectionUtil.isNotEmpty(result) && (result.get(0) & 1) == 1) {
                DateTime day = DateUtil.offsetDay(firstDay, i);
                signHistory.add(DateUtil.formatDate(day));
            }
        }
        return R.ok(signHistory);
    }

    /**
     * 今日签到积分
     */
    @GetMapping("/getTodayAmount")
    public R<BigDecimal> getTodayAmount() {
        Date now = new Date();
        Long userId = LoginHelper.getUserId();

        String[] amountList = configService.queryValueByKey("sign").split("-");
        //往前找amountList.length天
        BigDecimal amount = new BigDecimal(amountList[amountList.length - 1]);
        for (int i = 1; i < amountList.length + 1; i++) {
            Date day = DateUtil.offsetDay(now, -i);
            String keySuffix = DateUtil.format(day, ":yyyyMM:");
            String key = USER_SIGN_KEY + userId + keySuffix;

            int dayOfMonth = DateUtil.dayOfMonth(day);
            List<Long> result = stringRedisTemplate.opsForValue().bitField(key,
                BitFieldSubCommands.create()
                    .get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0));
            Boolean isSign = (result.get(0) & 1) == 1;
            if (!isSign) {
                //没签到
                amount = new BigDecimal(amountList[i - 1]);
                break;
            }
        }
        return R.ok(amount);
    }

    @GetMapping("/getUserInfo")
    public R<UserVo> getUserInfo(Long userId) {
        return R.ok(businessUserService.getUserInfo(userId));
    }

    private final ScheduledExecutorService scheduledExecutorService;

    /**
     * 入驻
     */
    @RepeatSubmit(interval = 1500, message = "入驻信息提交中...")
    @PostMapping("/join")
    public R<Void> join(String relName, String sex, String phone, String gameId, String gameArea, String gameName) {
        SysUser user = userService.getById(LoginHelper.getUserId());

        if (ObjectUtil.equal(user.getIsWaiter(), "1")) {
            return R.fail("您已经是打手了,请勿重复申请");
        }
        userService.lambdaUpdate()
            .set(SysUser::getRelName, relName)
            .set(SysUser::getSex, sex)
            .set(SysUser::getPhone, phone)
            .set(SysUser::getGameId, gameId)
            .set(SysUser::getGameArea, gameArea)
            .set(SysUser::getGameName, gameName)

            .set(SysUser::getIsWaiter, "2")
            .eq(SysUser::getUserId, LoginHelper.getUserId())
            .update();
        scheduledExecutorService.schedule(() -> {
            WebSocketUtils.sendMessage(UserConstants.SUPER_ADMIN_ID, relName + "申请入驻打手, 请及时审批!");
        }, 0, TimeUnit.SECONDS);
        return R.ok();
    }
}
